#include "Ray.h"

Ray::Ray(const Vector& newEyepoint, const Vector& newDirection, const Map& newMap)
: eyepoint(newEyepoint), direction(newDirection), map(newMap)
{
	DdaAlgorithm();
}

Ray::~Ray()
{
}

void Ray::DdaAlgorithm()
{
	//Cell where eyepoint is located
	Scalar mapX = eyepoint.GetX().GetInt();
	Scalar mapY = eyepoint.GetY().GetInt();

	//Distance from the current position of the ray to the next x or y-line
	Scalar rayDistX; 
	Scalar rayDistY;

	//The distance of the ray from 1 x- or y-line to the next x- or y-line
	Scalar dX = ((direction.GetY() * direction.GetY()) / (direction.GetX() * direction.GetX()) + 1).Sqrt();
	Scalar dY = ((direction.GetX() * direction.GetX()) / (direction.GetY() * direction.GetY()) + 1).Sqrt();
    Scalar perpWallDist;

	//X heading North (+1) or South (-1). Y heading West (-1) or East (1) 
	int xorientation;
	int yorientation;

	bool hit = false; //Intersection with wall?
	bool verticalhit; //True if the wall is hit on the west or east side. False if it's hit on the south or north side.

	//Check if we are heading north or south/west or east. And calculate the initial dX, dY 
	if (direction.GetX() < 0)
    {
		xorientation = -1;
		rayDistX = (eyepoint.GetX() - mapX) * dX;
    }
    else
    {
		xorientation = 1;
		rayDistX = (mapX + 1.0 - eyepoint.GetX()) * dX;
	}

	if (direction.GetY() < 0)
    {
		yorientation = -1;
		rayDistY = (eyepoint.GetY() - mapY) * dY;
    }
    else
    {
		yorientation = 1;
		rayDistY = (mapY + 1.0 - eyepoint.GetY()) * dY;
    }

	while (hit == 0)
    {                   
		
		if (dX < dY)
		{
			rayDistX += dX;
			mapX += xorientation;
			verticalhit = false;
		}
        else
        {
			rayDistY += dY;
			mapY += yorientation;
			verticalhit = true;
		}               
        
		if (!map.GetCell(mapX.GetInt(), mapY.GetInt())) 
		{
			hit = true;
		}
	}

	intersection.SetX(mapX);
	intersection.SetY(mapY);

	if(verticalhit == true)
		distance = ((mapX - eyepoint.GetX() + (1 - xorientation) / 2) / direction.GetX());
	else
		distance = ((mapY - eyepoint.GetY() + (1 - yorientation) / 2) / direction.GetY());
}

const Vector& Ray::GetIntersection() const
{
	return intersection;
}

const Scalar& Ray::GetDistance() const
{
	return distance;
}
